package base.thread_demo.demo19;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * synchronized 和 volatile(只能修饰全局的变量) 都可以保证共享变量的可见性。
 * static修饰的成员变量会放在主存中，线程在运行过程中会读取一份保存在自己的内存中，这是JIT编译器优化的结果。所以，
 * 当另外的线程修改了主存中该成员变量，对已经读取的线程来说，线程对该成员变量不可见，除非在成员变量前加了volatile，又或者
 * 线程中任务被放在了synchronized代码块这种重量级锁里面了。
 *
 * 不能log.info()输出，否则看不到线程僵住效果，原因解释如下：
 * log.info() 底层加了synchronize锁从而保证了可见性
 *
 */
public class VolatileDemo02 {
    private static final Logger log = LoggerFactory.getLogger(VolatileDemo02.class);
    //	volatile static boolean flag=true;
    static boolean flag=true;
    static final Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
//        test1();
        test2();
    }

    /**
     * 不能log.info()输出，否则看不到线程僵住效果，原因解释如下：
     * log.info() 底层加了synchronize锁从而保证了可见性
     */
    public static void test1() throws InterruptedException {
        Thread tt = new Thread(()->{
            while(true) {// log.info内部加了synchronized重量级锁
                if(!flag) {
                    log.info("{} break", Thread.currentThread().getName());
                    break;
                }
                // TODO 内部同步导致从主存中获取flag?
//				log.info("{} running...", Thread.currentThread().getName());
            }
        },"tt");
        tt.start();

        log.info("main 50ms后开始停止tt");
        Thread.sleep(50);
        flag = false;//不会如预想的让tt线程停下来的，除非volatile修饰了flag
        log.info("tt被停止？");
    }




    public static void test2() throws InterruptedException {
        Thread t1 = new Thread(()->{
            while(true) {
                synchronized (lock) {
                    if(!flag) {
                        break;
                    }
                }
            }
        });
        t1.start();

        log.info("main 50ms后开始停止t1");
        Thread.sleep(50);
        synchronized (lock) {
            flag = false;//会如预想的让t1线程停下来的
        }
        log.info("t1被停止");
    }
}
